/*
 * @Author       : liubangyi liubangliuyi@163.com
 * @Date         : 2024-07-16 10:20:56
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 13:12:25
 * @FilePath     : \openchaoji-corelib\shared\src\OpenChaoJi_utility_data_buff.c
 * @Description  : 本文件实现通用数据收发模块, 用于定时发送数据和接受缓存数据队列
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "../include/OpenChaoJi_shared.h"
#include "../include/OpenChaoJi_utility_data_buff.h"


#define DEFAULT_BUFFER_CAPACITY (4 * 2)

struct OpenChaoJi_utility_data_buff_node
{
    struct OpenChaoJi_utility_data_buff_send_data data;  // 发送数据
    uint32_t send_tick;                                  // 该数据上次发送时间戳
    struct OpenChaoJi_utility_data_buff_node *next;      // 指向下一个节点的指针
};

struct OpenChaoJi_context_utility_data_buff{
    int tag;

	struct OpenChaoJi_utility_data_buff_recv_data *recv_queue;
	unsigned int recv_capacity;   		//初始化时缓冲区队列容量(小于128时默认128)
	int recv_queue_head; 		//接收队列头位置
	int recv_queue_tail;

	struct OpenChaoJi_utility_data_buff_node  *send_list;
	int send_list_count;

};

static bool s_data_buff_debug_enabled = false;
void OpenChaoJi_debug_set_log_module_data_buff(bool enable)
{
    s_data_buff_debug_enabled = enable;
}

/**
* @brief 初始化数据缓冲区上下文
*
* @param info 初始化信息
* @return 成功返回创建的上下文指针，失败返回NULL。
*/
struct OpenChaoJi_context_utility_data_buff * OpenChaoJi_utility_data_buff_init(const struct OpenChaoJi_create_info_utility_data_buff * info)
{
    struct OpenChaoJi_context_utility_data_buff *context = OpenChaoJi_os_malloc(sizeof(struct OpenChaoJi_context_utility_data_buff));
    if (context == NULL) {
        LOG_CRIT("[%d]context malloc failed", info->tag);
        return NULL;
    }

    context->tag = info->tag;
    //如果初始化队列理论最大值*2 为缓冲区大小
    if(info->recv_capacity > 0)
    {
        context->recv_capacity = info->recv_capacity * 2;
    }
    else
    {
        context->recv_capacity = DEFAULT_BUFFER_CAPACITY;

    }
    //设定队列大小，申请接收数据队列并初始化
    context->recv_queue = OpenChaoJi_os_malloc(context->recv_capacity * sizeof(struct OpenChaoJi_utility_data_buff_recv_data));

    if (context->recv_queue == NULL) {
        LOG_CRIT("Failed to allocate memory for recv_queue");
        OpenChaoJi_os_free(context);
        return NULL;
    }
    context->recv_queue_head = 0;
    context->recv_queue_tail = 0;

    context->send_list = NULL;
    context->send_list_count = 0;

    LOG_ALERT("[%d]Buff Init capacity: %u", context->tag, context->recv_capacity);
    return context;
}

/**
* @brief 销毁数据缓冲区上下文
*
* @param context 系统上下文指针，包含必要的环境信息。
* @return 成功返回0，失败返回-1。
*/
int OpenChaoJi_utility_data_buff_term(struct OpenChaoJi_context_utility_data_buff * context) {
    if (context == NULL) {
        LOG_CRIT("Invalid context");
        return -1;
    }

    LOG_ALERT("[%d]Buff Terminated", context->tag);

    //销毁链表
    struct OpenChaoJi_utility_data_buff_node  *current = context->send_list;
    while (current != NULL) {
        struct OpenChaoJi_utility_data_buff_node *next = current->next;

        if (current->data.send_data.src_free == 0) { // 检查是否需要释放动态内存
            OpenChaoJi_os_free(current->data.send_data.data);
        }
        OpenChaoJi_os_free(current);
        current = next;
    }

    OpenChaoJi_os_free(context->recv_queue);
    OpenChaoJi_os_free(context);

    return 0;
}

/**
 * @brief 复位数据缓冲区上下文，清空收发缓冲区和队列
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_utility_data_buff_reset(struct OpenChaoJi_context_utility_data_buff * context) {
    if (context == NULL) {
        LOG_CRIT("Invalid context");
        return -1;
    }

    LOG_ALERT("[%d]Buff Reset", context->tag);

    context->recv_queue_head = 0;
    context->recv_queue_tail = 0;

    struct OpenChaoJi_utility_data_buff_node  *current = context->send_list;
    while (current != NULL) {
        struct OpenChaoJi_utility_data_buff_node  *next = current->next;
        if (current->data.send_data.src_free == 0) { // 检查是否需要释放动态内存
            OpenChaoJi_os_free(current->data.send_data.data);
        }
        OpenChaoJi_os_free(current);
        current = next;
    }
    context->send_list = NULL;
    context->send_list_count = 0;

    return 0;
}

/**
 * @brief 保存数据到接收队列
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @param write_data 待写入的接收数据
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_utility_data_buff_queue_write(struct OpenChaoJi_context_utility_data_buff * context, struct OpenChaoJi_utility_data_buff_recv_data * write_data) {
    if (context == NULL || write_data == NULL) {
        LOG_CRIT("Invalid context");
        return -1;
    }

    //循环队列，寻找下一个位置
    int next_tail = (context->recv_queue_tail + 1) % context->recv_capacity;
    if (next_tail == context->recv_queue_head) {
        LOG_ERR("[%d]recv_queue is full", context->tag);
        return -1; // 队列已满
    }

    //将传输层传入消息存进recv_queue，待应用层获取并释放 传输层需要赋值0 使用者释放
    context->recv_queue[context->recv_queue_tail] = *write_data;
    context->recv_queue_tail = next_tail;

    LOG_DEBUG("[%d]W->recv_queue[%d]", context->recv_queue_tail);
    if (s_data_buff_debug_enabled)
    {
        LOG_DATA_DATABUFF("[%d]WriteRecvQueue[%08X]free[%d]", context->tag, write_data->tag.all, write_data->recv_data.src_free);
        LOG_DATA_BUFF_DATABUFF(write_data->recv_data.data, write_data->recv_data.len);
    }

    return 0;
}

/**
 * @brief 从接收队列读取数据
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @param recv_data 待读取的数据结构
 * @return 读到数据返回0，读不到数据返回-1。
 */
int OpenChaoJi_utility_data_buff_queue_read(struct OpenChaoJi_context_utility_data_buff * context, struct OpenChaoJi_utility_data_buff_recv_data * recv_data) {
    if (context == NULL || recv_data == NULL) {
        LOG_CRIT("Invalid context or recv_data pointer");
        return -1;
    }
    if (context->recv_queue_head == context->recv_queue_tail) {
        // LOG_DEBUG("Receive queue is empty, no data to read");
        return -1; // 队列为空
    }

    //应用层释放 传输层需要赋值0 此处暂存
    *recv_data = context->recv_queue[context->recv_queue_head];
    //消息存入应用层接收结构体后，循环队列头指针向下移动一位
    context->recv_queue_head = (context->recv_queue_head + 1) % context->recv_capacity;

    LOG_DEBUG("R<-recv_queue[%d]", context->recv_queue_head);
    if (s_data_buff_debug_enabled)
    {
        LOG_DATA_DATABUFF("[%d]ReadRecvQueue[%08X]free[%d]", context->tag, recv_data->tag.all, recv_data->recv_data.src_free);
        LOG_DATA_BUFF_DATABUFF(recv_data->recv_data.data, recv_data->recv_data.len);
    }

    return 0;
}

/**
 * @brief 写入数据到发送区
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @param send_data 待发送的数据结构
 * @param stop_flag 设置为1时，设置cnt为0，停止发送
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_utility_data_buff_data_write(struct OpenChaoJi_context_utility_data_buff * context, struct OpenChaoJi_utility_data_buff_send_data * send_data, int stop_flag) {
    if (context == NULL || send_data == NULL) {
        LOG_CRIT("Invalid context or send_data pointer");
        return -1;
    }
    if (stop_flag == 1) {
        send_data->cnt = 0;
        LOG_DATA_CHANGE("Stop flag set, cnt set to 0");
    }

    // 遍历链表, 检查是否有相同的tag, 如果tag相同, 则覆盖本地发送区的数据
    struct OpenChaoJi_utility_data_buff_node *current = context->send_list;
    while (current != NULL) {
        if (current->data.tag.all == send_data->tag.all) {
            if (s_data_buff_debug_enabled)
            {
                LOG_DATA_DATABUFF("[%d]OverwriteSendQueue[%08X]free[%d]", context->tag, send_data->tag.all, send_data->send_data.src_free);
                LOG_DATA_BUFF_DATABUFF(send_data->send_data.data, send_data->send_data.len);
            }

            if (current->data.send_data.src_free == 0) { // 检查是否需要释放动态内存
                OpenChaoJi_os_free(current->data.send_data.data);
            }
            current->data = *send_data;
            return 0;
        }

        current = current->next;
    }

    //  创建新节点
    struct OpenChaoJi_utility_data_buff_node  *new_node = OpenChaoJi_os_malloc(sizeof(struct OpenChaoJi_utility_data_buff_node));
    if (new_node == NULL) {
        LOG_CRIT("Failed to allocate memory for new send node");
        return -1;
    }

    // 拷贝节点结构体数据
    new_node->data = *send_data;
    new_node->send_tick = 0;  // 初始化发送时间戳
    new_node->next = NULL;

    // // 将新节点插入到链表的头部
    // new_node->next = context->send_list;
    // context->send_list = new_node;
    // context->send_list_count++;
    // 如果链表为空，直接将新节点作为头节点
    if (context->send_list == NULL) {
        context->send_list = new_node;
    } else {
        // 遍历链表，找到最后一个节点
        struct OpenChaoJi_utility_data_buff_node *current = context->send_list;
        while (current->next != NULL) {
            current = current->next;
        }
        // 将新节点连接到最后一个节点的后面
        current->next = new_node;
    }

    context->send_list_count++;

    LOG_DEBUG("W->send_list[%d]", context->send_list_count);
    if (s_data_buff_debug_enabled)
    {
        LOG_DATA_DATABUFF("[%d]WriteSendQueue[%08X]free[%d]", context->tag, send_data->tag.all, send_data->send_data.src_free);
        LOG_DATA_BUFF_DATABUFF(send_data->send_data.data, send_data->send_data.len);
    }

    return 0;
}

/**
 * @brief 发送数据，检查发送队列并尝试发送数据
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @param write_func 发送数据的方法
 * @param param write_func方法所需要的私有参数
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_utility_data_buff_service_try_send(struct OpenChaoJi_context_utility_data_buff * context, int (*write_func)(void *param, struct OpenChaoJi_utility_data_buff_send_data * send_data), void * param) {

    if (context == NULL || write_func == NULL) {
        LOG_ERR("Invalid context or write_func pointer");
        return -1;
    }
    uint32_t current_tick  = OpenChaoJi_os_get_ticks();

    struct OpenChaoJi_utility_data_buff_node  *prev = NULL;//前一个节点
    struct OpenChaoJi_utility_data_buff_node  *current = context->send_list;//当前节点

    // 循环将发送队列数据发送出去
    while (current != NULL)
    {
        int time_diff = current_tick - current->send_tick;
        // 判断是否需要发送数据
        if ((current->data.cnt > 0 || current->data.cnt == -1) &&
            (current->data.interval_ms == 0 || time_diff >= current->data.interval_ms))
        {
            if (s_data_buff_debug_enabled)
            {
                LOG_DATA_DATABUFF("[%d]TrySend[%08X]free[%d]", context->tag, current->data.tag.all, current->data.send_data.src_free);
                LOG_DATA_BUFF_DATABUFF(current->data.send_data.data, current->data.send_data.len);
            }

            int result = write_func(param, &current->data);
            if (result == 0)
            {
                if (current->data.cnt > 0)
                {
                    current->data.cnt--;
                }
                current->send_tick = current_tick; // 更新发送时间戳
                LOG_DEBUG("Sent data with tag %d, remaining count: %d", current->data.tag, current->data.cnt);
            }
            else
            {
                // LOG_WARNING("[%d]TrySendFail[%08X]", context->tag, current->data.tag.all);

                // 未到发送时间 若需要等待，直接跳过
                prev = current;
                current = current->next;
                continue;
            }
        }

        // 无需发送，清空
        if (current->data.cnt == 0)
        {
            struct OpenChaoJi_utility_data_buff_node *to_delete = current;
            // 删除节点
            if (prev == NULL)
            {
                context->send_list = current->next;
            }
            else
            {
                prev->next = current->next;
            }
            current = current->next;
            if (to_delete->data.send_data.src_free == 0)
            {
                OpenChaoJi_os_free(to_delete->data.send_data.data); // 释放数据包
            }
            OpenChaoJi_os_free(to_delete);

            context->send_list_count--;
            LOG_DEBUG("Removed send node, new send_list count: %d", context->send_list_count);
        }
        else
        {
            prev = current;
            current = current->next;
        }
    }
    return 0;
}

